import React, {Component}       from 'react';
import path                     from 'path';
import {Button, message, Modal} from 'antd';
import './App.css';
import Support                  from './adb/support';
import Adb                      from "./adb/adb_command";
import FileInput                from "./components/FileInput";

const {remote} = require('electron');
let win        = remote.getCurrentWindow();

export default class App extends Component {

    constructor(props) {
        super(props);
        this.state  = {
            deviceOnLine: false,
            hasApk      : false,
            consoleLines: []
        };
        this.device = {
            sdk  : "",
            model: "",
            api  : 14
        };
        this.apk    = {
            name      : "",
            version   : "",
            pkg       : "",
            launcher  : "",
            path      : "",
            permission: []
        }
    }

    componentWillMount() {
        const s = Support.check();
        if (!s) {
            this.errorModal("应用已过期!", "应用已过期，如需要使用，请关注微信订阅号“测试一般不一般”获取!");
            return
        }
        this.refreshDevice();
        this.console(`当前路径: ${path.resolve('./')}`)
    }

    resetAll() {
        this.device = {
            sdk  : "",
            model: "",
            api  : 14
        };
        this.apk    = {
            name      : "",
            version   : "",
            pkg       : "",
            launcher  : "",
            path      : "",
            permission: []
        };
        this.setState({
            deviceOnLine: false,
            hasApk      : false,
            consoleLines: []
        });
        this.refreshDevice();
    }

    showVersion() {
        Modal.info({
            title  : "当前版本:",
            content: Support.version(),
        });
    }

    showHelp() {
        Modal.info({
            title  : "温馨提示:",
            content: "有疑问请关注微信公众号”测试一般不一般“进行交流"
        });
    }

    render() {
        const {deviceOnLine, hasApk, consoleLines} = this.state;
        const {model, sdk}                         = this.device;
        const {name, version, pkg, launcher}       = this.apk;
        return (
            <div className="at-main">
                <div>
                    <Button style={{marginLeft: "75%"}} size="small" onClick={() => this.showVersion()}>版本号</Button>
                    <Button style={{marginLeft: "3%"}} size="small" onClick={() => this.showHelp()}>帮助</Button>
                </div>
                <h1>应用启动时间专项测试</h1>
                <div className="at-device-info">
                    <div className="hori-line line-title ">
                        <span>设备信息:</span>
                        <Button style={{marginLeft: "10%"}} type="primary" onClick={() => this.refreshDevice()}>刷新设备</Button>
                        <Button style={{marginLeft: "40%"}} type="danger" onClick={() => this.resetAll()}>恢复初始化</Button>
                    </div>
                    {deviceOnLine &&
                    <div style={{marginTop: "1%"}}>
                        <span>型号 : {model}</span>
                        <span style={{marginLeft: "10%"}}>系统 : {sdk}</span>
                    </div>}
                </div>

                <div className="at-device-info">
                    <div className="hori-line line-title ">
                        <span style={{marginRight: "10%"}}>APK信息:</span>
                        <FileInput id="upload_apk" tag="上传apk" onFileSelected={file => this.loadApk(file)}/>
                    </div>
                    {
                        hasApk &&
                        <div style={{marginTop: "1%"}}>
                            <div>
                                <span>应用名 : {name}</span>
                                <span style={{marginLeft: "10%"}}>版本 : {version}</span>
                            </div>
                            <div>包名 : {pkg}</div>
                            <div>首页 : {launcher}</div>
                        </div>
                    }
                </div>

                <div className="at-device-info">
                    <div className="hori-line line-title">操作 :</div>
                    <div style={{display: "flex", justifyContent: "space-around"}}>
                        <Button disabled={!hasApk} onClick={() => this.install()}>安装</Button>
                        <Button disabled={!hasApk} onClick={() => this.clearApp()}>清除数据</Button>
                        <Button disabled={!hasApk} onClick={() => this.uninstall()}>卸载</Button>
                    </div>
                    <div style={{display: "flex", justifyContent: "space-around", marginTop: "2%"}}>
                        <Button disabled={!hasApk} onClick={() => this.launchApp()}>启动APP</Button>
                        <Button disabled={!hasApk} onClick={() => this.closeApp()}>关闭APP</Button>
                    </div>
                </div>

                <div className="console-module">
                    <div className="hori-line line-title">控制台</div>

                    <div className="console"
                         id="consoleLine"
                         style={{float: "left", clear: "both"}}
                    >
                        {
                            consoleLines.map(it => {
                                return (<span>{it}<br/></span>);
                            })
                        }
                    </div>
                </div>
            </div>
        )
    }

    async refreshDevice() {
        const devices = await Adb.devices();
        if (devices.length === 0) {
            this.toastError("无设备连接,请检查!");
            return
        } else if (devices.length > 1) {
            this.toastError("超过一台设备,请检查!");
            return
        }
        this.device.model = await Adb.brand() + "-" + await Adb.model();
        this.device.sdk   = await Adb.sdk();
        this.device.api   = await Adb.api();
        this.setState({deviceOnLine: true})
    }

    async loadApk(file) {
        this.console(`上传的文件: ${file.path}`);
        if (!file.path.endsWith(".apk")) {
            this.toastError("请上传APK文件");
            return
        }
        this.apk      = await Adb.xml(file.path);
        this.apk.path = file.path;
        this.setState({hasApk: true});
    }

    async install() {
        await this.refreshDevice();
        const {deviceOnLine} = this.state;
        if (!deviceOnLine) {
            this.toastError("设备连接异常,请检查!");
            return
        }
        this.console("设备状态正常!");

        const {pkg, path, permission} = this.apk;
        if (await Adb.pkgExist(pkg)) {
            await Adb.uninstall(pkg);
            this.console("卸载旧包!")
        }
        const arg    = this.device.api >= 23 ? "-g" : "";
        const result = await Adb.install(path, arg);
        if (result.data) {
            await Adb.grant(pkg, permission);
            this.toastSuccess("安装成功!")
        } else {
            if (result.err) {
                this.toastError(result.err);
            } else this.toastError("安装失败!")
        }
    }

    async uninstall() {
        await this.refreshDevice();
        const {deviceOnLine} = this.state;
        if (!deviceOnLine) {
            this.toastError("设备连接异常,请检查!");
            return
        }
        this.console("设备状态正常!");

        const {pkg} = this.apk;
        if (!await Adb.pkgExist(pkg)) {
            this.toastError("应用已经不存在,无需重复卸载!");
            return
        }
        if (await Adb.uninstall(pkg)) {
            this.toastSuccess("卸载成功!")
        } else this.toastError("卸载失败!")
    }

    async clearApp() {
        await this.refreshDevice();
        const {deviceOnLine} = this.state;
        if (!deviceOnLine) {
            this.toastError("设备连接异常,请检查!");
            return
        }
        this.console("设备状态正常!");

        const {pkg, permission} = this.apk;
        if (!await Adb.pkgExist(pkg)) {
            this.toastError("应用已经不存在,无法清除!");
            return
        }
        if (await Adb.clear(pkg)) {
            await Adb.grant(pkg, permission);
            this.toastSuccess("清除成功!")
        } else this.toastError("清除失败!")
    }

    async launchApp() {
        await this.refreshDevice();
        const {deviceOnLine} = this.state;
        if (!deviceOnLine) {
            this.toastError("设备连接异常,请检查!");
            return
        }
        this.console("设备状态正常!");

        const {pkg, launcher} = this.apk;
        if (!await Adb.pkgExist(pkg)) {
            this.toastError("应用已经不存在,无法启动!");
            return
        }
        const r = await Adb.launch(pkg, launcher);
        if (r) {
            this.toastSuccess("启动成功!");
            this.console(r)
        } else this.toastError("启动不成功!")
    }

    async closeApp() {
        await this.refreshDevice();
        const {deviceOnLine} = this.state;
        if (!deviceOnLine) {
            this.toastError("设备连接异常,请检查!");
            return
        }
        this.console("设备状态正常!");

        const {pkg} = this.apk;
        if (!await Adb.pkgExist(pkg)) {
            this.toastError("应用已经不存在,无法关闭!");
            return
        }
        if (!await Adb.appAlive(pkg)) {
            this.toastError("应用还没启动,无需关闭!");
            return
        }
        if (await Adb.close(pkg)) {
            this.toastSuccess("关闭成功!")
        } else this.toastError("关闭失败!")
    }

    console(output) {
        const {consoleLines} = this.state;
        const timestamp      = new Date().Format("yy-MM-dd hh:mm:ss") + " : ";
        const arr            = output.split("\n");
        arr.forEach(it => {
            if (it.trim().length !== 0)
                consoleLines.push(timestamp + it);
        });
        this.setState({consoleLines: consoleLines});
    }

    toastError(output) {
        this.console(output);
        message.error(output);
    }

    toastSuccess(output) {
        this.console(output);
        message.success(output);
    }

    errorModal(title, content) {
        Modal.error({
            title  : title,
            content: content,
            onOk() {
                win.close();
                process.exit(1)
            }
        });
    }

    scrollToBottom() {
        const ele     = document.getElementById('consoleLine');
        ele.scrollTop = ele.scrollHeight;
    }

    componentDidMount() {
        this.scrollToBottom();
    }

    componentDidUpdate() {
        this.scrollToBottom();
    }
}
